package com.example.gaoyang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.gaoyang.domain.SysElement;
import com.example.gaoyang.domain.SysRole;
import com.example.gaoyang.domain.SysRoleElement;
import com.example.gaoyang.domain.request.SysRoleElementRequest;
import com.example.gaoyang.domain.vo.SysRoleElementVO;
import com.example.gaoyang.enums.ResultEnum;
import com.example.gaoyang.exception.InvalidParameterException;
import com.example.gaoyang.mapper.SysRoleElementMapper;
import com.example.gaoyang.request.Result;
import com.example.gaoyang.service.SysElementService;
import com.example.gaoyang.service.SysRoleElementService;
import com.example.gaoyang.service.SysRoleService;
import com.example.gaoyang.util.ResultUtil;
import com.example.gaoyang.wrapper.SysRoleElementWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@Transactional
public class SysRoleElementServiceImpl extends ServiceImpl<SysRoleElementMapper, SysRoleElement> implements SysRoleElementService {

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysElementService sysElementService;

    @Override
    public void addSysRoleElement(SysRoleElementRequest sysRoleElementRequest) {
        // 角色id和系统元素id均不能为空
        Long roleId = sysRoleElementRequest.getRoleId();
        Long elementId = sysRoleElementRequest.getElementId();
        if (roleId == null || elementId == null) {
            throw new InvalidParameterException("参数roleId或elementId缺失");
        }
        // 确保角色id和系统元素id已存在
        SysRole sysRole = sysRoleService.getOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getId, roleId)
        );
        if (sysRole == null) {
            throw new InvalidParameterException("角色不存在");
        }
        SysElement sysElement = sysElementService.getOne(new LambdaQueryWrapper<SysElement>()
                .eq(SysElement::getId, elementId)
        );
        if (sysElement == null) {
            throw new InvalidParameterException("系统元素不存在");
        }
        // 添加的时候连带添加，如果添加了子菜单，相当于添加了父级菜单
        List<SysElement> allParentElement = sysElementService.getLinkParentElementById(elementId);
        // 获取权限元素关联表的所有数据，并将权限id_元素id抽取出来,只有当数据库中没有的时候才需要添加
        this.handleAddSysRoleElement(roleId, allParentElement);
    }

    @Override
    public void batchAddSysRoleElement(SysRoleElementRequest sysRoleElementRequest) {
        // 角色id和系统元素id均不能为空
        Long roleId = sysRoleElementRequest.getRoleId();
        if (roleId == null) {
            throw new InvalidParameterException("参数roleId缺失");
        }
        List<Long> elementIds = sysRoleElementRequest.getElementIds();
        if (CollectionUtil.isEmpty(elementIds)) {
            throw new InvalidParameterException("参数elementIds缺失");
        }
        // 添加的时候连带添加，如果添加了子菜单，相当于添加了父级菜单
        List<SysElement> allParentElement = sysElementService.getLinkParentElementByList(elementIds);
        // 获取权限元素关联表的所有数据，并将权限id_元素id抽取出来,只有当数据库中没有的时候才需要添加
        this.handleAddSysRoleElement(roleId, allParentElement);
    }

    @Override
    public void removeSysRoleElement(SysRoleElementRequest sysRoleElementRequest) {
        // 角色id和系统元素id均不能为空
        Long roleId = sysRoleElementRequest.getRoleId();
        Long elementId = sysRoleElementRequest.getElementId();
        if (roleId == null || elementId == null) {
            throw new InvalidParameterException("参数roleId或elementId缺失");
        }
        // 确保角色id和系统元素id已存在
        SysRole sysRole = sysRoleService.getOne(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getId, roleId)
        );
        if (sysRole == null) {
            throw new InvalidParameterException("角色不存在");
        }
        SysElement sysElement = sysElementService.getOne(new LambdaQueryWrapper<SysElement>()
                .eq(SysElement::getId, elementId)
        );
        if (sysElement == null) {
            throw new InvalidParameterException("系统元素不存在");
        }
        // 删除的时候连带删除，如果删除了父级菜单，相当于删除了子菜单
        List<SysElement> allLinkElement = sysElementService.getLinkChildElementById(elementId);
        // 获取权限元素关联表的所有数据，并将权限id_元素id抽取出来构建成map,只有当数据库中存在的时候才需要删除
        this.handleRemoveSysRoleElement(roleId, allLinkElement);
    }

    @Override
    public void batchRemoveSysRoleElement(SysRoleElementRequest sysRoleElementRequest) {
        // 角色id和系统元素id均不能为空
        Long roleId = sysRoleElementRequest.getRoleId();
        if (roleId == null) {
            throw new InvalidParameterException("参数roleId缺失");
        }
        List<Long> elementIds = sysRoleElementRequest.getElementIds();
        if (CollectionUtil.isEmpty(elementIds)) {
            throw new InvalidParameterException("参数elementIds缺失");
        }
        // 删除的时候连带删除，如果删除了父级菜单，相当于删除了子菜单
        List<SysElement> allLinkElement = sysElementService.getLinkChildElementByList(elementIds);
        // 获取权限元素关联表的所有数据，并将权限id_元素id抽取出来构建成map,只有当数据库中存在的时候才需要删除
        this.handleRemoveSysRoleElement(roleId, allLinkElement);
    }

    /**
     * 此方法将会传入更新的权限系统元素列表，再来判断是删除还是新增
     * @param sysRoleElementRequest
     * @return
     */
    @Override
    public void batchUpdateSysRoleElement(SysRoleElementRequest sysRoleElementRequest) {
        // 角色id和系统元素id均不能为空
        Long roleId = sysRoleElementRequest.getRoleId();
        if (roleId == null) {
            throw new InvalidParameterException("参数roleId缺失");
        }
        List<Long> elementIds = sysRoleElementRequest.getElementIds();
        if (CollectionUtil.isEmpty(elementIds)) {
            throw new InvalidParameterException("参数elementIds缺失");
        }
        // 添加的时候连带添加，如果添加了子菜单，相当于添加了父级菜单
        List<SysElement> newList = sysElementService.getLinkParentElementByList(elementIds);
        // 原来的角色元素关联表数据
        List<SysRoleElement> oldList = this.list(new LambdaQueryWrapper<SysRoleElement>()
                .eq(SysRoleElement::getRoleId, roleId)
        );
        // 添加列表为在newList中且不在oldList中的元素
        List<SysElement> addElement = newList.stream()
                .filter(newListElement -> oldList.stream().noneMatch(oldListElement -> oldListElement.getElementId().equals(newListElement.getId())))
                .collect(Collectors.toList());
        List<SysRoleElement> addList = new ArrayList<>();
        addElement.forEach(addItem -> {
            SysRoleElement sysRoleElement = new SysRoleElement();
            sysRoleElement.setId(IdUtil.getSnowflake().nextId());
            sysRoleElement.setRoleId(roleId);
            sysRoleElement.setElementId(addItem.getId());
            sysRoleElement.setCreateTime(new Date());
            addList.add(sysRoleElement);
        });
        this.saveBatch(addList);
        // 删除列表为在oldList中且不在newList中的元素
        List<SysRoleElement> deleteList = oldList.stream()
                .filter(oldListElement -> newList.stream().noneMatch(newListElement -> newListElement.getId().equals(oldListElement.getElementId())))
                .collect(Collectors.toList());
        this.removeBatchByIds(deleteList);
    }

    @Override
    public List<SysRoleElementVO> getSysRoleElementList(SysRoleElementRequest sysRoleElementRequest) {
        LambdaQueryWrapper<SysRoleElement> wrapper = this.createWrapper(sysRoleElementRequest);
        List<SysRoleElement> list = this.list(wrapper);
        return BeanUtil.copyToList(list, SysRoleElementVO.class);
    }

    @Override
    public IPage<SysRoleElementVO> getSysRoleElementPage(IPage<SysRoleElement> page, SysRoleElementRequest sysRoleElementRequest) {
        page.setCurrent(sysRoleElementRequest.getPageNum());
        page.setSize(sysRoleElementRequest.getPageSize());
        return new SysRoleElementWrapper().pageVO(this.page(page, this.createWrapper(sysRoleElementRequest)));
    }

    /**
     * 添加角色元素关联表数据
     * @param roleId
     * @param allParentElement
     */
    private void handleAddSysRoleElement(Long roleId, List<SysElement> allParentElement) {
        // 获取权限元素关联表的所有数据，并将权限id_元素id抽取出来,只有当数据库中没有的时候才需要添加
        List<String> dataIdentity = this.list(new LambdaQueryWrapper<SysRoleElement>()
                .select(SysRoleElement::getRoleId, SysRoleElement::getElementId)
        ).stream().map(roleElement -> roleElement.getRoleId() + "_" + roleElement.getElementId()).collect(Collectors.toList());
        List<SysRoleElement> sysRoleElementsAdd = new ArrayList<>();
        for (SysElement element : allParentElement) {
            // 判断是否已存在,不存在才添加
            if (!dataIdentity.contains(roleId + "_" + element.getId())) {
                SysRoleElement sysRoleElement = new SysRoleElement();
                // 赋值权限id
                sysRoleElement.setRoleId(roleId);
                // 赋值系统元素id
                sysRoleElement.setElementId(element.getId());
                sysRoleElement.setId(IdUtil.getSnowflake().nextId());
                sysRoleElement.setCreateTime(new Date());
                sysRoleElementsAdd.add(sysRoleElement);
            }
        }
        this.saveBatch(sysRoleElementsAdd);
    }

    /**
     * 删除角色元素关联表数据
     * @param roleId
     * @param allLinkElement
     */
    private void handleRemoveSysRoleElement(Long roleId, List<SysElement> allLinkElement) {
        // 获取权限元素关联表的所有数据，并将权限id_元素id抽取出来构建成map,只有当数据库中存在的时候才需要删除
        Map<String, SysRoleElement> dataIdentityMap = this.list(new LambdaQueryWrapper<SysRoleElement>()
                .select(SysRoleElement::getId, SysRoleElement::getRoleId, SysRoleElement::getElementId)
        ).stream().collect(Collectors.toMap(roleElement -> roleElement.getRoleId() + "_" + roleElement.getElementId(), roleElement -> roleElement));
        List<String> dataIdentity = new ArrayList<>(dataIdentityMap.keySet());
        List<SysRoleElement> sysRoleElementsRemove = new ArrayList<>();
        for (SysElement element : allLinkElement) {
            String key = roleId + "_" + element.getId();
            if (dataIdentity.contains(key)) {
                SysRoleElement sysRoleElement = new SysRoleElement();
                // 赋值权限id
                sysRoleElement.setRoleId(roleId);
                // 赋值系统元素id
                sysRoleElement.setElementId(element.getId());
                Long id = dataIdentityMap.get(roleId + "_" + element.getId()).getId();
                sysRoleElement.setId(id);
                sysRoleElementsRemove.add(sysRoleElement);
            }
        }
        this.removeBatchByIds(sysRoleElementsRemove);
    }

    private LambdaQueryWrapper<SysRoleElement> createWrapper(SysRoleElementRequest sysRoleElementRequest) {
        return new LambdaQueryWrapper<SysRoleElement>()
                .in(CollectionUtil.isNotEmpty(sysRoleElementRequest.getRoleIds()), SysRoleElement::getRoleId, sysRoleElementRequest.getRoleIds())
                .eq(CollectionUtil.isNotEmpty(sysRoleElementRequest.getElementIds()), SysRoleElement::getElementId, sysRoleElementRequest.getElementIds())
                .orderByDesc(SysRoleElement::getCreateTime);
    }
}
